package com.pruebas.physics.dragablemomentumsimplegravity;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import com.pruebas.physics.common.Rectangle;
import com.pruebas.physics.common.Square;
import com.pruebas.physics.common.SurfaceMapper;
import com.pruebas.physics.common.TwoAxisMomentum;


import android.opengl.GLSurfaceView;
import android.opengl.GLU;

public class DragableMomentumSimpleGravityRenderer implements GLSurfaceView.Renderer {
	private SurfaceMapper surfaceMapper;
	
	private Square objy;
	private Rectangle floor;
	
	private static final float airResistance = 0.01f;
	private static final float floorFriction = 0.95f;
	private static final float gravity = -0.5f;
	private static final float defaultTimeDelta = 0.5f;
	private float timeDelta = defaultTimeDelta;
	
	private float objyLastXSpeed = 0f;
	private float objyLastYSpeed = 0f;
	private float objyLastXPos = 0f;
	private float objyLastYPos = 0f;
	
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		// Set the background frame color
        gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
        // initialize the rectangle vertex array
        initShapes();
        // Enable use of vertex arrays
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    }
    
    public void onDrawFrame(GL10 gl) {
    	// Redraw background color
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        
        TwoAxisMomentum objyMomentum = this.CalculateNewCoordinates(objyLastXPos, objyLastYPos, objyLastXSpeed, objyLastYSpeed, timeDelta); 
	    float objyXPos = objyMomentum.getxPos();
        float objyYPos = objyMomentum.getyPos();
	    
        objyLastXSpeed = objyMomentum.getXSpeed();
        objyLastYSpeed = objyMomentum.getYSpeed();
        objyLastXPos = objyXPos;
        objyLastYPos = objyYPos;
        
        //Objy
        gl.glPushMatrix();
        gl.glColor4f(0f, 1f, 1f, 0.0f);
        gl.glTranslatef(objyXPos - objy.getInitialX(), objyYPos - objy.getInitialY(), 0);
        objy.draw(gl);
        gl.glPopMatrix();
        
        //Floor
        gl.glPushMatrix();
        gl.glColor4f(1f, 0f, 1f, 0.0f);
        floor.draw(gl);
        gl.glPopMatrix();
    }
    
    public void onSurfaceChanged(GL10 gl, int width, int height) {
    	this.surfaceMapper = new SurfaceMapper(width, height, 5f);
    	
    	gl.glViewport(0, 0, width, height);
        
        // make adjustments for screen ratio
        gl.glMatrixMode(GL10.GL_PROJECTION);        // set matrix to projection mode
        gl.glLoadIdentity();                        // reset the matrix to its default state
        gl.glFrustumf(-this.surfaceMapper.getRatio(), this.surfaceMapper.getRatio(), -1, 1, 1f, 10);  // apply the projection matrix
        
        gl.glMatrixMode(GL10.GL_PROJECTION);
        gl.glLoadIdentity();
        
        this.floor = new Rectangle(this.surfaceMapper.getMagicX() * 2, 2f, 0f, -this.surfaceMapper.getMagicY());
        GLU.gluOrtho2D(gl,
        		-this.surfaceMapper.getMagicX(), this.surfaceMapper.getMagicX(),
        		-this.surfaceMapper.getMagicY(), this.surfaceMapper.getMagicY());
        
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity(); // reset the matrix to its default state
        // When using GL_MODELVIEW, you must set the view point
        GLU.gluLookAt(gl, 0, 0, -1f, 0f, 0f, 0f, 0f, 1f, 0.0f);

    }
    
    public Boolean isTouchingObjy(float x, float y){
    	float[] mappedCoords = this.surfaceMapper.mapCoordinates(x, y);
    	float mappedX = mappedCoords[0];
    	float mappedY = mappedCoords[1];
    	
    	float distanceX = Math.abs(this.objyLastXPos - mappedX); 
		float distanceY = Math.abs(this.objyLastYPos - mappedY);
		float halfSide = this.objy.getSide() /2;
		return (distanceX <= halfSide && distanceY <= halfSide);
    }
    
    public void setObjyMomentum(float x, float y){
    	float[] mappedCoords = this.surfaceMapper.mapCoordinates(x, y);
    	float mappedX = mappedCoords[0];
    	float mappedY = mappedCoords[1];
    	
    	float xSpeed = (mappedX - this.objyLastXPos) * 2;
    	float ySpeed = (mappedY - this.objyLastYPos) * 2.5f;
    	
    	TwoAxisMomentum objyMomentum = this.CalculateNewCoordinates(mappedX, mappedY, xSpeed, ySpeed, 0);
    	
    	this.objyLastXPos = objyMomentum.getxPos();
    	this.objyLastYPos = objyMomentum.getyPos();
    	this.objyLastXSpeed = objyMomentum.getXSpeed();
    	this.objyLastYSpeed = objyMomentum.getYSpeed();
    }
    
    public void stopTime() {
		this.timeDelta = 0f;
		this.objyLastXSpeed = 0f;
		this.objyLastYSpeed = 0f;
	}
    
    public void resumeTime() {
		this.timeDelta = defaultTimeDelta;
	}
    
    public boolean isTimeStopped(){
    	return this.timeDelta == 0f;
    }
    
    private void initShapes(){
    	this.objyLastXPos = -2f;
    	this.objyLastYPos = 3f;
    	this.objy = new Square(1.5f, objyLastXPos, objyLastYPos);
    }
    
    private TwoAxisMomentum CalculateNewCoordinates(float lastXPos, float lastYPos, float lastXSpeed, float lastYSpeed, float elapsedTime){
    	float xResistance = airResistance;
    	
    	float objyYSpeed = lastYSpeed + gravity * elapsedTime;        
        float objyYPos = lastYPos + objyYSpeed * elapsedTime;
        float floorTop = floor.getInitialY() + floor.getHeight() / 2;
        float objyButtom = objyYPos - objy.getSide() / 2;
        if(objyButtom <= floorTop){
        	objyYSpeed *= -0.7;
        	objyYPos = floorTop + objy.getSide() / 2;
        	xResistance += floorFriction;
        }    	
    	
    	float objyXSpeed = Math.abs(lastXSpeed) - airResistance * elapsedTime;
    	if(Math.abs(lastXSpeed) - xResistance * elapsedTime <= 0){
    		objyXSpeed = 0;
    	}else{
    		if(lastXSpeed < 0){
    			objyXSpeed *= -1;
    		}
    	}
		float objyXPos = lastXPos + objyXSpeed * elapsedTime;
		if(Math.abs(objyXPos) + objy.getSide() / 2 >= this.surfaceMapper.getMagicX()){
			objyXSpeed *= -0.7f;
			if(objyXPos >= 0){
				objyXPos = this.surfaceMapper.getMagicX() - objy.getSide() / 2;
			}else{
				objyXPos = -this.surfaceMapper.getMagicX() + objy.getSide() / 2;
			}
		}
    	
    	TwoAxisMomentum objyMomentum = new TwoAxisMomentum(objyXPos, objyYPos, objyXSpeed, objyYSpeed);
    	return objyMomentum;
    }
    
}
